HDU 1503 [Advanced Fruits] LCS

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1503

题目大意:给出两个单词,要求凑出一个新单词,并且这个新单词包含前两个单词(存在子序列与前两个单词相同)并且长度最短

关键思想:其实要让长度最短,我们所能省掉的只有1遍LCS,另外的字母都不能省略。LCS,递推方程:当a[i]==b[j]时,dp[i][j]=dp[i-1][j-1]+1(末位相等,那末位一定是LCS元素之一嘛),否则dp[i][j]=max{dp[i-1][j],dp[i][j-1]}.据此得到d数组后,从i,j开始向前走,并处理剩余部分就OK了。

代码如下:

#include <iostream>
#include <string>
#include <memory.h>
using namespace std;
const int MAXN=105;

int d[MAXN][MAXN];//保存递推方向 
int c[MAXN][MAXN];//LCS长度 
string ans;

void LCS(string a,string b){
    memset(d,0,sizeof(d));
    for(int i=0;i<=a.size();i++)c[i][0]=0;
    for(int i=0;i<=b.size();i++)c[0][i]=0;
    
    for(int i=1;i<=a.size();i++){
        for(int j=1;j<=b.size();j++){
            if(a[i-1]==b[j-1]){
                c[i][j]=c[i-1][j-1]+1;
                d[i][j]=0;//0斜 
            }else{
                if(c[i-1][j]>c[i][j-1]){
                    c[i][j]=c[i-1][j];
                    d[i][j]=1;//1上 
                }
                else{
                    c[i][j]=c[i][j-1];
                    d[i][j]=2;//2左 
                }
            }
        }
    }
    return;
}

void output(string a,string b){//根据d数组得到最大公共子序列 
    int i=a.size(),j=b.size();
    ans="";
    while(i>0&&j>0){
        if(d[i][j]==0){
            ans+=a[i-1]; 
            i--,j--;
        }
        if(d[i][j]==1){
            ans+=a[i-1];
            i--;
        }
        if(d[i][j]==2){
            ans+=b[j-1];
            j--;
        }
    }
    while(i>0)ans+=a[i-1],i--;
    while(j>0)ans+=b[j-1],j--;//处理剩余部分 
    
    for(int i=ans.size()-1;i>=0;i--){
        cout<<ans[i];
    }//逆序输出 
    cout<<endl; 
    return;
} 

int main(){
    string a,b;
    while(cin>>a>>b){
        LCS(a,b); 
        output(a,b);
    }
    return 0;
} 

 

posted @ 2017-08-12 20:14  哇咔咔咔  阅读(233)  评论(0编辑  收藏  举报